<?php
declare(strict_types=1);

namespace App\Aspect;

use App\BaseResponse;
use App\Enum\Code;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Resource\Json\JsonResource;
use Hyperf\Resource\Json\ResourceCollection;
use Hyperf\Utils\Codec\Json;

#[Aspect(annotations: [
    Controller::class,
    AutoController::class
])]
class WrapResponseAspect extends AbstractAspect
{
    #[Inject]
    private ResponseInterface $response;

    public function process(ProceedingJoinPoint $proceedingJoinPoint)
    {
        $result = $proceedingJoinPoint->process();

        if ($result instanceof BaseResponse) {
            return $this->response->withBody(new SwooleStream((string) $result))->withStatus($result->code->getHttpCode());
        } elseif ($result instanceof ResourceCollection) {
            $body = $result->toResponse()->getBody();
            return $this->response->json(new BaseResponse(
                Code::OK,
                'Ok',
                Json::decode((string) $body),
            ));
        } elseif ($result instanceof JsonResource) {
            return $this->response->json(new BaseResponse(
                Code::OK,
                'Ok',
                $result->withoutWrapping()->toArray(),
            ));
        } elseif (is_array($result)) {
            return $this->response->json(new BaseResponse(
                Code::OK,
                'Ok',
                $result,
            ));
        } else {
            return $result;
        }
    }
}